#ifndef __UVTHREAD_H
#define __UVTHREAD_H

#include <cstdio>
#include <pthread.h>
#include <cstdint>
#include <list>

namespace uv {
namespace thread {

/**
 * The recurrent thread class is a virtual class providing an easy interface
 * for implementing a thread that waits for a signal to perform a task. To
 * implement, simply define the workings of the task function.
 */
class RecurrentThread {
public:
    /**
     * Build the recurrent thread object, create the thread, and initialize
     * the mutexes.
     */
    RecurrentThread();

    /**
     * Force the thread to exit and destroy all mutexes.
     */
    ~RecurrentThread();

    /**
     * The main loop of the thread. This loops waits for a signal then checks
     * for any tasks such as performing a tick or terminating execution.
     *
     * @return Always returns 0.
     */
    void *mainLoop();

    /**
     * Since class member functions can't be used in threads, this static
     * function is used.
     *
     * @param context A void pointer to a RecurrentThread context.
     * @return The value returned from {@ref mainLoop}.
     */
    static void *mainLoopHelper(void *context);

    /**
     * Tells this object to perform its operation with a given parameter. If
     * the object is currently busy, the tick operation will be queued.
     *
     * @param arg A void pointer to the argument to be passed to the task
     *          function.
     * @return True if the task was scheduled. This funciton can fail if a task
     *          was already scheduled via the {@ref tickBlocking) function
     *          and not executed.
     */
    bool tick(void *arg);

    /**
     * Tells this object to perform its operation with a given parameter.
     *
     * @param arg A void pointer to the argument to be passed to the task
     *          function.
     * @return True if the task was scheduled. This funciton can fail if a task
     *          was already scheduled and not executed.
     */
    bool tickBlocking(void *arg);

    /**
     * Tells this object that it should kill the thread.
     */
    void stop();

    /**
     * This function calls the {@ref stop} function then joins the thread and
     * blocks until the thread is joined.
     */
    void join();

    /**
     * Tells if the thread is currently still running.
     *
     * @return True if the {@ref mainLoop} function is still running.
     */
    bool isRunning();

    /**
     * Tells if the thread is ready for another tick.
     *
     * @return True if the thread is still running and the tick flag is not set.
     */
    bool isReady();

    /**
     * @return The RecurrentThread ID.
     */
    size_t getId();

    /**
     * This is the task that will execute for each successful call to
     * {@ref tick}.
     *
     * @param arg The argument passed into the {@ref tick} function.
     */
    virtual void task(void *arg) = 0;
private:
    /** The total number of threads created by this class. */
    static size_t thread_count;

    /** The cached copy of the argument to pass to {@ref task}. */
    std::list<void*> task_args;

    /** The thread being used by this object. */
    pthread_t thread;

    /** The ID of the thread being used by this object. */
    size_t tid;

    /** The current flags set for the thread to perform. */
    uint8_t flags;

    /** Tells the main loop to stop execution. */
    static const uint8_t STOP_FLAG = 1;

    /** Tells the main loop to peform a {@ref task} call. */
    static const uint8_t TICK_FLAG = 1 << 1;

    /** Tells the main loop to only perform a single {@ref task} call. */
    static const uint8_t ONE_TICK_FLAG = 1 << 2;

    /** Tells that the main loop is done and the thread is not running. */
    static const uint8_t DONE_FLAG = 1 << 7;

    /** Mutex used to protect the flags. */
    pthread_mutex_t flag_mutex;

    /** Conditional variable used to signal flag changes. */
    pthread_cond_t flag_cv;
};

} // namespace thread
} // namespace uv
#endif // __UVTHREAD_H
